#ifndef RTE_OS_KSERIAL_H
#define RTE_OS_KSERIAL_H
#undef write
#undef read

#include "nStream.h"
#include "firmata.pb.h"
#include "mFirmata.h"

#ifdef ARDUINO

#include <Arduino.h>

#else

#define SERIAL_8N1 0x06
#define SERIAL_8N2 0x0E
#define SERIAL_7E1 0x24
#define SERIAL_8E1 0x26
#define SERIAL_7E2 0x2C
#define SERIAL_8E2 0x2E
#define SERIAL_7O1 0x34
#define SERIAL_8O1 0x36
#define SERIAL_7O2 0x3C
#define SERIAL_8O2 0x3E
#define SERIL_BUF_SIZE 256
#endif
using u8 = unsigned char;
using u16 = unsigned short;
using uint32_t = uint32_t;

class kSerial : public nStream {
public:
    kSerial() {
        // 空串口
#ifdef ARDUINO
#else
        iFd = -1;
#endif
    }

#ifdef ARDUINO_ARCH_STM32

    explicit kSerial(USART_TypeDef *name);

    kSerial(PinName rx, PinName tx, bool txinv = false, bool rxinv = false, bool swap = false) {
        _serial.pin_tx = tx;
        _serial.pin_rx = rx;
        flag = (txinv ? TX_INV : 0) | (rxinv ? RX_INV : 0) | (swap ? TX_RX_SWAP : 0);
    }

    kSerial(u8 rx, u8 tx, bool txinv = false, bool rxinv = false, bool swap = false, uint32_t init_baud = 0) {
        _serial.pin_tx = digitalPinToPinName(tx);
        _serial.pin_rx = digitalPinToPinName(rx);
        flag = (txinv ? TX_INV : 0) | (rxinv ? RX_INV : 0) | (swap ? TX_RX_SWAP : 0);
        if (init_baud > 0) {
            begin(init_baud);
        }
    }

    serial_t _serial{};

    static void _rx_complete_irq(serial_t *obj);

#endif


    kSerial(const char *);

#ifdef ARDUINO

    explicit kSerial(Stream *serial);

#endif

    virtual ~kSerial() = default;

    virtual int begin(unsigned int baud, u8 config = SERIAL_8N1, int rx_buff_sz = 256, int tx_buff_sz = 256);

    int available_wait(int Delay) override;

    int available() override;

    static kSerial *get_serial(int fd);

    int availableForWrite() override;

    int write(const u8 *buffer, int size) override;

    int write(uint8_t ch) override;

    int read() override;

    int read_wait(int timeout = -1) override;

    int peek() override;

    void flush() override;

    int diag();

    int begin_transmit();

    int end_transmit();

    int begin_receive();

    int end_receive();

#ifndef THIS_IS_BOOTLOADER

    void set_low();

    void set_high();

    void set_rx();

    virtual int end();

#endif

    uint32_t baud() const;

    u8 stop_bits() const;

    u8 parity() const;

    u8 data_bits() const;

    int tx_max_size() override {
        return 256;
    }

    static kSerial *get_mon_serial();

    static kSerial *get_firmata_serial();

    static kSerial *Serials[SERIAL_NRS];
    static const u8 Serials_nrs;
    const char *name{};
#ifdef ARDUINO
#else
    int iFd;
    char pcBuff[SERIL_BUF_SIZE];
#endif

#ifdef HAL_IRDA_MODULE_ENABLED
    u8 _sd_pin = 0;

    void setIRDA(int SD_PIN);

#endif
    void *rx_lock{};

    void enableHalfDuplexRx();

    bool isHalfDuplex() const;

    bool _rx_enabled{};
    bool _written{};
#ifdef ARDUINO_ARCH_STM32

    static int _tx_complete_irq(serial_t *obj);

    void set_pin(int tx_pin, int rx_pin, int de_pin = -1);

    void set_pin(PinName tx_pin, PinName rx_pin);

#endif

    virtual int sleep() {
    };

    void configForLowPower();

    pb_serial data;
    uint32_t write_count = 0;

    static void get_info(mFirmata *mf, nStream *ns, byte cmd, uint16_t argc, byte *argv);

    void *tmr_rx;

    static void _serial_tmr_cb(void *arg);

    bool timer_is_running;
    bool wait;
#ifdef ARDUINO
    PinName pin_de;
#endif
};

#endif // RTE_OS_KSERIAL_H
